
import java.util.HashMap;
import java.util.LinkedList;

/**
 *
 * @author Jah Emanuel
 */
public class ImplicitEnumeration {

    private static HashMap<Integer, String> mappingIndexesToValues;
    private static LinkedList<LinkedList<String>> solution;
    private static boolean isDirected;

    public static LinkedList<LinkedList<String>> solveGraph(Graph graph) {
        solution=new LinkedList<LinkedList<String>>();
        mappingIndexesToValues = graph.getMappingIndexesToValues();
        isDirected=graph.isDirected();
        if (graph.isDirected()) {
            solveNonDirectedGraph(graph);
        } else {
            solveNonDirectedGraph(graph);
        }
        return solution;
    }

    private static void solveDirectedGraph(Graph graph) {
        int[] horizontalSum = graph.getHorizontalSum();


        int maxIndex;


    }

    private static void solveNonDirectedGraph(Graph graph) {
        int[] horizontalSum = graph.getHorizontalSum().clone();
        int[][] matrix = graph.getGraph();
        int maxSlots = graph.getMaxSlots();
        int maxIndex;
        int assignedSlot;
        boolean[] assignedIndexes=new boolean[matrix.length];
        while(!areAllAssigned(assignedIndexes)) {
            maxIndex = maxIndex(horizontalSum);
            
            LinkedList<Integer> prohibitionsToNode=graph.getProhibitions().get(maxIndex);
            assignedSlot=assignSpaceToNode(assignedIndexes,horizontalSum,prohibitionsToNode, maxSlots, maxIndex);
            forbidSlotToChildren(assignedIndexes,graph.getProhibitions(),assignedSlot, matrix[maxIndex],horizontalSum, maxSlots);
        }
    }
    
    private static void forbidSlotToChildren(boolean[] assignedIndexes,LinkedList<LinkedList<Integer>> prohibitions,int assignedSlot, int[] arrayConnections,int[] horizontalSum, int maxSlots){
        LinkedList<Integer> prohibitionsToNode;
        for (int j = 0; j < arrayConnections.length; j++) {
            if(!assignedIndexes[j] && arrayConnections[j]==1){
                horizontalSum[j]--;
                prohibitionsToNode=prohibitions.get(j);
                if(!prohibitionsToNode.contains(assignedSlot)){
                    prohibitionsToNode.add(assignedSlot);
                }
                if(horizontalSum[j]==0 && !isDirected){
                    assignSpaceToNode(assignedIndexes,horizontalSum,prohibitionsToNode, maxSlots, j);
                }
            }   
        }
    }

    private static int assignSpaceToNode(boolean[] assignedIndexes,int[] horizontalSum, LinkedList<Integer> prohibitionsToNode, int maxSlots, int nodeIndex) {
        LinkedList<String> slot;
        int i;
        assignedIndexes[nodeIndex]=true;
        horizontalSum[nodeIndex] = Integer.MIN_VALUE;
        for (i = 0; true; i++) {
            try {
                solution.get(i);
            } catch (IndexOutOfBoundsException e) {
                solution.add(i, new LinkedList<String>());
            }
            if (!prohibitionsToNode.contains(i)) {
                slot = solution.get(i);
                if (slot.size() >= maxSlots) 
                    continue;
                slot.add(mappingIndexesToValues.get(nodeIndex));
                break;
            }
        }
        return i;
    }
    
    private static boolean areAllAssigned(boolean [] assignedIndexes){
        for (boolean b : assignedIndexes) {
            if(!b)
                return false;
        }
        return true;
    }

    private static int maxIndex(int[] array) {
        if (array.length < 1) {
            return -1;
        }
        int max = 0;
        for (int i = 1; i < array.length; i++) {
            if (array[max] < array[i]) {
                max = i;
            }
        }
        return max;
    }

    public static String stringSolution() {
        StringBuilder sb = new StringBuilder();
        int i = 1;
        sb.append("\nSolution\n");
        for (LinkedList<String> linkedList : solution) {
            sb.append(String.format("%03d", i) + ": ");
            for (String string : linkedList) {
                sb.append(string + ",");
            }
            sb.append("\n");
            i++;
        }
        return sb.toString();
    }
}
